home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / misc / volume8 / rpn_eg < prev    next >
Encoding:
Text File  |  1989-08-27  |  31.1 KB  |  1,272 lines

  1. Newsgroups: comp.sources.misc
  2. subject: v08i021: Rpn v1.1
  3. From: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
  4. Reply-To: egray@fthood.UUCP
  5.  
  6. Posting-number: Volume 8, Issue 21
  7. Submitted-by: egray@fthood.UUCP
  8. Archive-name: rpn_eg
  9.  
  10. [I see a few "questional" preprocessor constructs in this code.  ++bsa]
  11.  
  12. Rpn is a public domain "pop up" reverse polish notation calculator that
  13. is designed to have the same (dare I say?) "look and feel" of the
  14. Hewlett-Packard HP-16c.  It can compile on virtually any flavor of Unix
  15. and MSDOS.  The MSDOS version will require the public domain PC Curses
  16. package.
  17.  
  18. I've included both the nroff version of the Unix manual page and the
  19. "ASCII'ized" version for folks (like MSDOS) without the Document Writers
  20. Workbench.  A makefile isn't required... it's only one file.
  21.  
  22. Have fun...
  23.  
  24. Emmet P. Gray                US Army, HQ III Corps & Fort Hood
  25. ...!uunet!uiucuxc!fthood!egray        Attn: AFZF-DE-ENV
  26. fthood!egray@uxc.cso.uiuc.edu        Directorate of Engineering & Housing
  27.                     Environmental Management Office
  28.                     Fort Hood, TX 76544-5057
  29.  
  30. ------------------------------------------------------------------------------
  31. #! /bin/sh
  32. # This is a shell archive, meaning:
  33. # 1. Remove everything above the #! /bin/sh line.
  34. # 2. Save the resulting text in a file.
  35. # 3. Execute the file with /bin/sh (not csh) to create:
  36. #    rpn.c
  37. #    rpn.1
  38. #    rpn.man
  39. # This archive created: Fri Aug 25 14:51:23 1989
  40. export PATH; PATH=/bin:/usr/bin:$PATH
  41. echo shar: "extracting 'rpn.c'" '(19008 characters)'
  42. if test -f 'rpn.c'
  43. then
  44.     echo shar: "will not over-write existing file 'rpn.c'"
  45. else
  46. sed 's/^X//' << \SHAR_EOF > 'rpn.c'
  47. X/*
  48. X * Simple RPN (Reverse Polish Notation) calculator.  Layout and functions
  49. X * loosely modeled after the HP-16c.  MSDOS versions will require the
  50. X * PC Curses package.
  51. X *
  52. X * on Unix compile with:
  53. X *     cc -O [-f] -s rpn.c -o rpn -lm -lcurses [-ltermcap] [-lc_s]
  54. X *
  55. X * Emmet P. Gray            US Army, HQ III Corps & Fort Hood
  56. X * ...!uunet!uiucuxc!fthood!egray    Attn: AFZF-DE-ENV
  57. X * fthood!egray@uxc.cso.uiuc.edu    Directorate of Engineering & Housing
  58. X *                     Environmental Management Office
  59. X *                     Fort Hood, TX 76544-5057
  60. X */
  61. X
  62. X#undef OLD_CURSES            /* for old Xenix and Berkeley */
  63. X#undef MSDOS                /* for MSDOS (requires PC Curses) */
  64. X#undef XENIX_3                /* for old Xenix 3.0/3.5 */
  65. X#undef BIG_END_FIRST            /* for Intel style CPU's */
  66. X#undef ANSI_C                /* for ANSI C */
  67. X
  68. X#include <stdio.h>
  69. X#include <math.h>
  70. X#include <curses.h>
  71. X
  72. X#ifdef ANSI_C
  73. X#include <limits.h>
  74. X#include <float.h>
  75. X#else /* ANSI_C */
  76. X#define LONG_MAX    0x7fffffff
  77. X#define ULONG_MAX    0xffffffff
  78. X#define DBL_DIG        15
  79. X#define DBL_MAX        1.7976931348623167e+308
  80. X#endif /* ANSI_C */
  81. X
  82. X#define DBL_ULONG_MAX    4294967295.0        /* ULONG_MAX as a double */
  83. X
  84. X#ifdef OLD_CURSES
  85. X#define wattron(win,A_REVERSE) wstandout(win)
  86. X#define wattroff(win,A_REVERSE) wstandend(win)
  87. X#define wattrset(win,A_NORMAL) wstandend(win)
  88. X#define cbreak crmode
  89. Xchar tb[1024];
  90. X#endif /* OLD_CURSES */
  91. X
  92. X#ifdef MSDOS
  93. X#define what_is_at(w,a,b) (w->_line[a][b])
  94. X#define getenv strdup
  95. X#else /* MSDOS */
  96. X#define what_is_at(w,a,b) (w->_y[a][b])
  97. X#endif /* MSDOS */
  98. X                    /* some fundamental contstants */
  99. X#define MAX_LOGICAL        0xffffffff
  100. X#define SCREEN_SIZE        36
  101. X#define STACK_SIZE        5
  102. X#define MAX_FLOAT_DIGITS    SCREEN_SIZE-1
  103. X#define MAX_HEX_DIGITS        8
  104. X#define MAX_OCTAL_DIGITS    11
  105. X#define MAX_DECIMAL_DIGITS    10
  106. X#define MAX_BINARY_DIGITS    32
  107. X#define DECIMAL_PLACES        8
  108. X                    /* operating modes */
  109. X#define FLOAT    0
  110. X#define HEX    1
  111. X#define DECIMAL    2
  112. X#define OCTAL    3
  113. X#define BINARY    4
  114. X                    /* location of calculator on screen */
  115. X#define BASE_Y    5
  116. X#define BASE_X    0
  117. X
  118. Xstruct layout {
  119. X    char key;
  120. X    int y;
  121. X    int x;
  122. X};
  123. X
  124. Xdouble stack[STACK_SIZE] = {0.0};
  125. Xdouble sto[10] = {0.0};
  126. Xchar blank[SCREEN_SIZE + 1];
  127. X
  128. Xmain(argc, argv)
  129. Xint argc;
  130. Xchar *argv[];
  131. X{
  132. X    int i, mode, store_it, position, over_flow, x, y, help_is_showing;
  133. X    int got_decimal, got_exponent, want_out, decimal_places;
  134. X    unsigned long int_part, dtoul();
  135. X    double op2, current, pop(), convert();
  136. X    char c, c1, input[SCREEN_SIZE], *strchr(), *memset(), *term, *getenv();
  137. X    char output[SCREEN_SIZE + 1], *bitpattern(), last_operator, *strcpy();
  138. X    void push(), exit(), paint_calc(), flash_key(), clear_display();
  139. X    WINDOW *win, *hwin, *help(), *newwin();
  140. X
  141. X                    /* initialize the terminal */
  142. X    term = getenv("TERM");
  143. X    if (term == NULL || *term == '\0') {
  144. X        printf("%s: TERM not defined...\n", argv[0]);
  145. X        exit(1);
  146. X    }
  147. X                    /* i=1 required for PC curses */
  148. X    i = 1;
  149. X#ifdef OLD_CURSES
  150. X    i = tgetent(tb, term);
  151. X#else /* OLD_CURSES */
  152. X    setupterm(term, 1, &i);
  153. X#endif /* OLD_CURSES */
  154. X    if (i != 1) {
  155. X        printf("%s: No terminfo data for '%s'...\n", argv[0], term);
  156. X        exit(1);
  157. X    }
  158. X    initscr();
  159. X    cbreak();
  160. X    noecho();
  161. X#ifdef XENIX_3
  162. X    raw();
  163. X#endif /* XENIX_3 */
  164. X                    /* percision in the display */
  165. X    if (argc > 1 && *argv[1] == '-') {
  166. X        decimal_places = atoi(&argv[1][1]);
  167. X        if (decimal_places < 0)
  168. X            decimal_places = 0;
  169. X        if (decimal_places > DBL_DIG)
  170. X            decimal_places = DBL_DIG;
  171. X    }
  172. X    else
  173. X        decimal_places = DECIMAL_PLACES;
  174. X
  175. X    win = newwin(15, 47, BASE_Y, BASE_X);
  176. X    paint_calc(win);
  177. X
  178. X    memset(blank, ' ', SCREEN_SIZE);
  179. X    blank[SCREEN_SIZE] = '\0';
  180. X    current = 0.0;
  181. X    position = 0;
  182. X    mode = FLOAT;
  183. X    help_is_showing = 0;
  184. X    last_operator = 0;
  185. X    got_decimal = 0;
  186. X    got_exponent = 0;
  187. X    want_out = 0;
  188. X
  189. X    while (1) {
  190. X        c = wgetch(win);
  191. X                    /* erase the help window */
  192. X        if (help_is_showing) {
  193. X            help_is_showing = 0;
  194. X            werase(hwin);
  195. X            wrefresh(hwin);
  196. X            delwin(hwin);
  197. X
  198. X            touchwin(win);
  199. X            wrefresh(win);
  200. X        }
  201. X
  202. X        store_it = 0;
  203. X        over_flow = 0;
  204. X                    /* get incoming digits */
  205. X        switch (mode) {
  206. X            case FLOAT:
  207. X                if (strchr("0123456789.eE+-", c) != NULL)
  208. X                    store_it++;
  209. X                switch (c) {
  210. X                    case '.':
  211. X                        if (got_decimal || got_exponent)
  212. X                            store_it = 0;
  213. X                        got_decimal++;
  214. X                        break;
  215. X                    case 'e':
  216. X                    case 'E':
  217. X                        if (!position || got_exponent)
  218. X                            store_it = 0;
  219. X                        got_exponent++;
  220. X                        break;
  221. X
  222. X                        /*
  223. X                         * Is it an operator or is it
  224. X                         * the sign of the exponent?
  225. X                         */
  226. X                    case '+':
  227. X                    case '-':
  228. X                        if (!position || (input[position - 1] != 'e' && input[position - 1] != 'E'))
  229. X                            store_it = 0;
  230. X                        break;
  231. X                }
  232. X                if (position >= MAX_FLOAT_DIGITS)
  233. X                    over_flow++;
  234. X                break;
  235. X            case HEX:
  236. X                if (strchr("0123456789abcdef", c) != NULL)
  237. X                    store_it++;
  238. X                if (position >= MAX_HEX_DIGITS)
  239. X                    over_flow++;
  240. X                break;
  241. X            case OCTAL:
  242. X                if (strchr("01234567", c) != NULL)
  243. X                    store_it++;
  244. X                if (position >= MAX_OCTAL_DIGITS)
  245. X                    over_flow++;
  246. X                break;
  247. X            case DECIMAL:
  248. X                if (strchr("0123456789", c) != NULL)
  249. X                    store_it++;
  250. X                if (position >= MAX_DECIMAL_DIGITS)
  251. X                    over_flow++;
  252. X                break;
  253. X            case BINARY:
  254. X                if (strchr("01", c) != NULL)
  255. X                    store_it++;
  256. X                if (position >= MAX_BINARY_DIGITS)
  257. X                    over_flow++;
  258. X                break;
  259. X        }
  260. X                    /* store digits */
  261. X        if (store_it) {
  262. X            if (over_flow) {
  263. X                fputc(7, stderr);
  264. X                continue;
  265. X            }
  266. X            flash_key(win, c);
  267. X            if (!position)
  268. X                clear_display(win);
  269. X            waddch(win, c);
  270. X            wrefresh(win);
  271. X
  272. X            input[position++] = c;
  273. X            input[position] = '\0';
  274. X            continue;
  275. X        }
  276. X                    /* process pseudo operators */
  277. X        switch (c) {
  278. X            case 'q':    /* time to quit? */
  279. X            case 'Q':
  280. X                want_out++;
  281. X                break;
  282. X            case '\b':    /* do a backspace */
  283. X                if (position) {
  284. X                    input[--position] = '\0';
  285. X                    flash_key(win, c);
  286. X                    getyx(win, y, x);
  287. X                    x--;
  288. X                    wmove(win, y, x);
  289. X                    waddch(win, ' ');
  290. X                    wmove(win, y, x);
  291. X                    wrefresh(win);
  292. X                }
  293. X                else
  294. X                    fputc(7, stderr);
  295. X                continue;
  296. X            case '?':    /* help! */
  297. X                flash_key(win, c);
  298. X                hwin = help();
  299. X                help_is_showing = 1;
  300. X                continue;
  301. X            default:
  302. X                break;
  303. X        }
  304. X        if (want_out)
  305. X            break;
  306. X                    /* test for valid operator */
  307. X        if (strchr("/FhHDoOB*&|lLxX\r\n-^~sSrRC+", c) == NULL) {
  308. X            fputc(7, stderr);
  309. X            continue;
  310. X        }
  311. X                    /* if you've got input, convert it */
  312. X        if (position) {
  313. X            current = convert(input, mode);
  314. X
  315. X            /*
  316. X             * This is a little weird... if the last operator was
  317. X             * the <enter>, then replace (rather than push) the
  318. X             * value on stack.
  319. X             */
  320. X            if (last_operator == '\r' || last_operator == '\n')
  321. X                stack[0] = current;
  322. X            else
  323. X                push(current);
  324. X
  325. X            position = 0;
  326. X            input[0] = '\0';
  327. X            got_decimal = 0;
  328. X            got_exponent = 0;
  329. X        }
  330. X                    /* process "real" operators */
  331. X        switch (c) {
  332. X            case '\r':
  333. X            case '\n':
  334. X                push(current);
  335. X                break;
  336. X            case '+':
  337. X                current = pop() + pop();
  338. X                push(current);
  339. X                break;
  340. X            case '-':
  341. X                op2 = pop();
  342. X                current = pop() - op2;
  343. X                push(current);
  344. X                break;
  345. X            case '*':
  346. X                current = pop() * pop();
  347. X                push(current);
  348. X                break;
  349. X            case '/':
  350. X                op2 = pop();
  351. X                if (op2 == 0.0) {
  352. X                    clear_display(win);
  353. X                    mvwaddstr(win, 3, 5, "divide by zero");
  354. X                    wrefresh(win);
  355. X                    continue;
  356. X                }
  357. X                current = pop() / op2;
  358. X                push(current);
  359. X                break;
  360. X            case 'C':    /* change sign */
  361. X                current = pop() * -1.0;
  362. X                push(current);
  363. X                break;
  364. X            case 'F':    /* float */
  365. X                mode = FLOAT;
  366. X                mvwaddch(win, 3, SCREEN_SIZE + 5, ' ');
  367. X                wmove(win, 3, 5);
  368. X                break;
  369. X            case 'h':
  370. X            case 'H':    /* hex */
  371. X                mode = HEX;
  372. X                mvwaddch(win, 3, SCREEN_SIZE + 5, 'h');
  373. X                wmove(win, 3, 5);
  374. X                break;
  375. X            case 'D':    /* decimal */
  376. X                mode = DECIMAL;
  377. X                mvwaddch(win, 3, SCREEN_SIZE + 5, 'd');
  378. X                wmove(win, 3, 5);
  379. X                break;
  380. X            case 'o':
  381. X            case 'O':    /* octal */
  382. X                mode = OCTAL;
  383. X                mvwaddch(win, 3, SCREEN_SIZE + 5, 'o');
  384. X                wmove(win, 3, 5);
  385. X                break;
  386. X            case 'B':    /* binary */
  387. X                mode = BINARY;
  388. X                mvwaddch(win, 3, SCREEN_SIZE + 5, 'b');
  389. X                wmove(win, 3, 5);
  390. X                break;
  391. X            case '&':    /* and */
  392. X                int_part = dtoul(pop()) & dtoul(pop());
  393. X                current = int_part;
  394. X                push(current);
  395. X                break;
  396. X            case '|':    /* or */
  397. X                int_part = dtoul(pop()) | dtoul(pop());
  398. X                current = int_part;
  399. X                push(current);
  400. X                break;
  401. X            case '^':    /* exclusive or */
  402. X                int_part = dtoul(pop()) ^ dtoul(pop());
  403. X                current = int_part;
  404. X                push(current);
  405. X                break;
  406. X            case '~':    /* 1's complement */
  407. X                int_part = (~dtoul(pop()) & MAX_LOGICAL);
  408. X                current = int_part;
  409. X                push(current);
  410. X                break;
  411. X            case 'x':
  412. X            case 'X':    /* xchg x and y */
  413. X                op2 = pop();
  414. X                current = pop();
  415. X                push(op2);
  416. X                push(current);
  417. X                break;
  418. X            case 's':
  419. X            case 'S':    /* store */
  420. X                flash_key(win, c);
  421. X                c1 = wgetch(win);
  422. X                if (strchr("0123456789", c1) == NULL) {
  423. X                    fputc(7, stderr);
  424. X                    continue;
  425. X                }
  426. X                    /* doesn't disturb the stack */
  427. X                sto[c1 - '0'] = current;
  428. X                break;
  429. X            case 'r':
  430. X            case 'R':    /* recall */
  431. X                flash_key(win, c);
  432. X                c1 = wgetch(win);
  433. X                if (strchr("0123456789", c1) == NULL) {
  434. X                    fputc(7, stderr);
  435. X                    continue;
  436. X                }
  437. X                current = sto[c1 - '0'];
  438. X                push(current);
  439. X                break;
  440. X            case 'l':
  441. X            case 'L':    /* roll the stack */
  442. X                op2 = stack[0];
  443. X                for (i = 0; i < STACK_SIZE - 1; i++)
  444. X                    stack[i] = stack[i + 1];
  445. X                stack[STACK_SIZE - 1] = op2;
  446. X                current = stack[0];
  447. X                break;
  448. X            default:
  449. X                fputc(7, stderr);
  450. X                continue;
  451. X        }
  452. X        last_operator = c;
  453. X                    /* display operator key */
  454. X        flash_key(win, c);
  455. X                    /* convert double to unsigned long */
  456. X        if (mode != FLOAT)
  457. X            int_part = dtoul(current);
  458. X
  459. X        /*
  460. X         * Dectect overflows in float mode only.  It's OK to overflow
  461. X         * in the hex/dec/oct/bin modes.
  462. X         */
  463. X        if (mode == FLOAT && fabs(current) >= DBL_MAX) {
  464. X            clear_display(win);
  465. X            mvwaddstr(win, 3, 5, "overflow");
  466. X            wrefresh(win);
  467. X            continue;
  468. X        }
  469. X                    /* print the answer */
  470. X        switch (mode) {
  471. X            case FLOAT:
  472. X                sprintf(output, "%.*g", decimal_places, current);
  473. X                break;
  474. X            case HEX:
  475. X                sprintf(output, "%lx", int_part);
  476. X                break;
  477. X            case OCTAL:
  478. X                sprintf(output, "%lo", int_part);
  479. X                break;
  480. X            case DECIMAL:
  481. X                sprintf(output, "%lu", int_part);
  482. X                break;
  483. X            case BINARY:
  484. X                strcpy(output, bitpattern(int_part));
  485. X                break;
  486. X        }
  487. X        clear_display(win);
  488. X        waddstr(win, output);
  489. X        wmove(win, 3, 5);
  490. X        wrefresh(win);
  491. X    }
  492. X
  493. X#ifdef OLD_CURSES
  494. X    move(LINES - 1, 0);
  495. X    refresh();
  496. X#endif /* OLD_CURSES */
  497. X    endwin();
  498. X    exit(0);
  499. X}
  500. X
  501. X/*
  502. X * Push a number on the stack.  If the stack is full, the "top" value
  503. X * is lost.
  504. X */
  505. X
  506. Xvoid
  507. Xpush(f)
  508. Xdouble f;
  509. X{
  510. X    int i;
  511. X
  512. X    for (i = STACK_SIZE - 1; i > 0; i--)
  513. X        stack[i] = stack[i - 1];
  514. X    stack[0] = f;
  515. X    return;
  516. X}
  517. X
  518. X/*
  519. X * Pop a value off the stack.  The "top" value is always preserved.
  520. X */
  521. X
  522. Xdouble
  523. Xpop()
  524. X{
  525. X    int i;
  526. X    double f;
  527. X
  528. X    f = stack[0];
  529. X    for (i = 0; i < STACK_SIZE - 1; i++)
  530. X        stack[i] = stack[i + 1];
  531. X    return (f);
  532. X}
  533. X
  534. X/*
  535. X * Convert a double to an unsigned long.  Some (most?) systems will generate
  536. X * a FPE (Floating Point Exception) if you attempt to assign a double that
  537. X * is greater than LONG_MAX.
  538. X */
  539. X
  540. Xunsigned long
  541. Xdtoul(d)
  542. Xdouble d;
  543. X{
  544. X    double temp;
  545. X    unsigned long ans;
  546. X                    /* is it too big for assignment? */
  547. X    if (fabs(d) > LONG_MAX) {
  548. X                    /* chop it to a resonable size */
  549. X        temp = fmod(d, DBL_ULONG_MAX);
  550. X        /*
  551. X         * if the fmod() returns a zero, then the number is just too
  552. X         * big to fit any useful information in 32 bits.
  553. X         */
  554. X        if (temp == 0.0)
  555. X            ans = ULONG_MAX;
  556. X        else {
  557. X            if (temp > LONG_MAX) {
  558. X                ans = (temp - LONG_MAX);
  559. X                ans += LONG_MAX;
  560. X            }
  561. X            else
  562. X                ans = temp;
  563. X        }
  564. X                    /* boundary condition at zero */
  565. X        if (temp != 0.0 && d > DBL_ULONG_MAX)
  566. X            ans -= 1L;
  567. X    }
  568. X    else                /* gee, isn't this soooo much easier? */
  569. X        ans = d;
  570. X
  571. X    return (ans & MAX_LOGICAL);
  572. X}
  573. X
  574. X/*
  575. X * Convert an ascii "number" into a double.  Handles hex/oct/bin digits.
  576. X */
  577. X
  578. Xdouble
  579. Xconvert(buf, mode)
  580. Xchar *buf;
  581. Xint mode;
  582. X{
  583. X    double f, atof();
  584. X    unsigned long strtoul();
  585. X
  586. X    switch (mode) {
  587. X        case DECIMAL:
  588. X        case FLOAT:
  589. X            f = atof(buf);
  590. X            break;
  591. X        case HEX:
  592. X            f = (double) strtoul(buf, (char **) NULL, 16);
  593. X            break;
  594. X        case OCTAL:
  595. X            f = (double) strtoul(buf, (char **) NULL, 8);
  596. X            break;
  597. X        case BINARY:
  598. X            f = (double) strtoul(buf, (char **) NULL, 2);
  599. X            break;
  600. X    }
  601. X    return (f);
  602. X}
  603. X
  604. X/*
  605. X * Convert a number into its binary bit pattern.  Returns a pointer to
  606. X * a static buffer.  The BIG_END_FIRST pre-processor macro determines if
  607. X * the number is stored "big end first" on your processor.
  608. X */
  609. X
  610. Xchar *
  611. Xbitpattern(val)
  612. Xunsigned long val;
  613. X{
  614. X    unsigned char c, *p;
  615. X    int i, j, size, printed, bp;
  616. X    static char bitbuf[SCREEN_SIZE];
  617. X
  618. X                    /* max of 32 bits  */
  619. X    size = sizeof(val);
  620. X    if (size > 4)
  621. X        size = 4;
  622. X
  623. X    p = (unsigned char *) &val;
  624. X#ifdef BIG_END_FIRST
  625. X    p += size - 1;
  626. X#endif /* BIG_END_FIRST */
  627. X
  628. X    bp = 0;
  629. X    printed = 0;
  630. X    for (i = 1; i <= size; i++) {
  631. X        c = *p;
  632. X#ifdef BIG_END_FIRST
  633. X        p--;
  634. X#else /* BIG_END_FIRST */
  635. X        p++;
  636. X#endif /* BIG_END_FIRST */
  637. X        if (c == 0 && !printed && i != size)
  638. X            continue;
  639. X        for (j = 7; j >= 0; j--)
  640. X            bitbuf[bp++] = ((c >> j) & 1) ? '1' : '0';
  641. X        if (i != size)
  642. X            bitbuf[bp++] = ' ';
  643. X        printed++;
  644. X    }
  645. X    bitbuf[bp++] = '\0';
  646. X    return (bitbuf);
  647. X}
  648. X
  649. X/*
  650. X * Put a key in inverse video.  This routine leaves the key in inverse video
  651. X * until the next key is pressed.
  652. X */
  653. Xstruct layout button[] = {
  654. X    'a', 6, 3,    'b', 6, 7,    'c', 6, 11,   'd', 6, 15,   'e', 6, 19,
  655. X    'f', 6, 23,   '7', 6, 28,   '8', 6, 32,   '9', 6, 36,   '/', 6, 40,
  656. X    '?', 8, 3,    'F', 8, 7,    'h', 8, 11,   'H', 8, 11,   'D', 8, 15,
  657. X    'o', 8, 19,   'O', 8, 19,   'B', 8, 23,   '4', 8, 28,   '5', 8, 32,
  658. X    '6', 8, 36,   '*', 8, 40,   '&', 10, 3,   '|', 10, 7,   'l', 10, 11,
  659. X    'L', 10, 11,  'x', 10, 15,  'X', 10, 15,  '\b', 10, 19, '\n', 10, 23,
  660. X    '\r', 10, 23, '1', 10, 28,  '2', 10, 32,  '3', 10, 36,  '-', 10, 40,
  661. X    'q', 12, 3,   'Q', 12, 3,   '^', 12, 7,   '~', 12, 11,  's', 12, 15,
  662. X    'S', 12, 15,  'r', 12, 19,  'R', 12, 19,  '0', 12, 28,  '.', 12, 32,
  663. X    'C', 12, 36,  '+', 12, 40,  '\0', 0, 0};
  664. X
  665. Xvoid
  666. Xflash_key(win, c)
  667. XWINDOW *win;
  668. Xchar c;
  669. X{
  670. X    int i, n, temp_x, old_x, old_y;
  671. X    static int last_y = 0, last_x = 0;
  672. X    static char keybuf[3];
  673. X                    /* get x, y coordinates */
  674. X    n = 0;
  675. X    while (button[n].key != '\0') {
  676. X        if (button[n].key == c)
  677. X            break;
  678. X        n++;
  679. X    }
  680. X    if (button[n].key == '\0')
  681. X        return;
  682. X
  683. X    getyx(win, old_y, old_x);
  684. X                    /* undo last button */
  685. X    if (last_y) {
  686. X        if (last_y == 10 && last_x == 23) {
  687. X            for (i = 0; i < 3; i++) {
  688. X                wmove(win, i + 10, 23);
  689. X                wattrset(win, A_NORMAL);
  690. X                waddstr(win, "<cr>");
  691. X            }
  692. X        }
  693. X        else {
  694. X            wmove(win, last_y, last_x);
  695. X            wattrset(win, A_NORMAL);
  696. X            waddstr(win, keybuf);
  697. X        }
  698. X    }
  699. X                    /* the enter key is 3x4 chars */
  700. X    if (button[n].y == 10 && button[n].x == 23) {
  701. X        for (i = 0; i < 3; i++) {
  702. X            wmove(win, i + 10, 23);
  703. X            wattron(win, A_REVERSE);
  704. X            waddstr(win, "<cr>");
  705. X            wattroff(win, A_REVERSE);
  706. X        }
  707. X    }
  708. X    else {                /* flash a button */
  709. X        wmove(win, button[n].y, button[n].x);
  710. X        wattron(win, A_REVERSE);
  711. X        temp_x = button[n].x;
  712. X        for (i = 0; i < 3; i++) {
  713. X            keybuf[i] = what_is_at(win, button[n].y, temp_x++);
  714. X            waddch(win, keybuf[i]);
  715. X        }
  716. X        wattroff(win, A_REVERSE);
  717. X    }
  718. X    wrefresh(win);
  719. X
  720. X    wmove(win, old_y, old_x);
  721. X    last_y = button[n].y;
  722. X    last_x = button[n].x;
  723. X    return;
  724. X}
  725. X
  726. X/*
  727. X * The image of the calculator.
  728. X */
  729. X
  730. Xvoid
  731. Xpaint_calc(win)
  732. XWINDOW *win;
  733. X{
  734. X    void mybox();
  735. X    int i;
  736. X
  737. X    waddstr(win, "                                              \n");
  738. X    waddstr(win, "    Reverse Polish Notation calculator v1.1   \n");
  739. X    waddstr(win, "   +---------------------------------------+  \n");
  740. X    waddstr(win, "   |                                       |  \n");
  741. X    waddstr(win, "   +---------------------------------------+  \n");
  742. X    waddstr(win, "                                              \n");
  743. X    waddstr(win, "    a   b   c   d   e   f    7   8   9   /    \n");
  744. X    waddstr(win, "                                              \n");
  745. X    waddstr(win, "    ?  Flt Hex Dec Oct Bin   4   5   6   *    \n");
  746. X    waddstr(win, "                                              \n");
  747. X    waddstr(win, "    &   |  roL  Xy  ^H <cr>  1   2   3   -    \n");
  748. X    waddstr(win, "                       <cr>                   \n");
  749. X    waddstr(win, "   Quit ^   ~  Sto Rcl <cr>  0   .  Chs  +    \n");
  750. X    waddstr(win, "                                              \n");
  751. X
  752. X    /*
  753. X     * If you've got line drawing characters, build a box around the
  754. X     * calculator display, replacing the crude one above.
  755. X     */
  756. X#ifdef ACS_VLINE
  757. X    for (i = 3; i < SCREEN_SIZE + 7; i++) {
  758. X        mvwaddch(win, 2, i, ACS_HLINE);
  759. X        mvwaddch(win, 4, i, ACS_HLINE);
  760. X    }
  761. X    mvwaddch(win, 3, 3, ACS_VLINE);
  762. X    mvwaddch(win, 3, SCREEN_SIZE + 7, ACS_VLINE);
  763. X                    /* fix up corners */
  764. X    mvwaddch(win, 2, 3, ACS_ULCORNER);
  765. X    mvwaddch(win, 2, SCREEN_SIZE + 7, ACS_URCORNER);
  766. X    mvwaddch(win, 4, 3, ACS_LLCORNER);
  767. X    mvwaddch(win, 4, SCREEN_SIZE + 7, ACS_LRCORNER);
  768. X#endif /* ACS_VLINE */
  769. X
  770. X    mybox(win);
  771. X    wmove(win, 3, 5);
  772. X    wrefresh(win);
  773. X    return;
  774. X}
  775. X
  776. X/*
  777. X * A box() routine that will fix up the corners if your version of
  778. X * curses is too stupid to do that itself.
  779. X */
  780. X
  781. Xvoid
  782. Xmybox(win)
  783. XWINDOW *win;
  784. X{
  785. X#ifdef ACS_VLINE
  786. X    box(win, 0, 0);
  787. X#else /* ACS_VLINE */
  788. X    box(win, '|', '-');
  789. X    mvwaddch(win, 0, 0, '+');
  790. X    mvwaddch(win, 0, win->_maxx - 1, '+');
  791. X    mvwaddch(win, win->_maxy - 1, 0, '+');
  792. X    mvwaddch(win, win->_maxy - 1, win->_maxx - 1, '+');
  793. X#endif /* ACS_VLINE */
  794. X    return;
  795. X}
  796. X
  797. X/*
  798. X * Clear the calculator "display" by writing blanks to it.  Does not
  799. X * clear the hex/oct/dec/bin flag at the end.
  800. X */
  801. X
  802. Xvoid
  803. Xclear_display(win)
  804. XWINDOW *win;
  805. X{
  806. X    mvwaddstr(win, 3, 5, blank);
  807. X    wmove(win, 3, 5);
  808. X    wrefresh(win);
  809. X    return;
  810. X}
  811. X
  812. X/*
  813. X * The help screen... it really only gives a list of the abbreviations.
  814. X */
  815. X
  816. XWINDOW *
  817. Xhelp()
  818. X{
  819. X    WINDOW *hwin, *newwin();
  820. X    void mybox();
  821. X
  822. X    hwin = newwin(14, 46, 2, 34);
  823. X    waddstr(hwin, "\n             RPN v1.1 - 18 Aug 89\n\n");
  824. X    waddstr(hwin, "     +  add              &  logical and\n");
  825. X    waddstr(hwin, "     -  subtract         |  logical or\n");
  826. X    waddstr(hwin, "     *  multiply         ^  exclusive or\n");
  827. X    waddstr(hwin, "     /  divide           ~  1's complement\n");
  828. X    waddstr(hwin, "    <cr> enter key      Chs change sign\n");
  829. X    waddstr(hwin, "    Flt float mode      Sto store [0-9]\n");
  830. X    waddstr(hwin, "    Hex hex mode        Rcl recall [0-9]\n");
  831. X    waddstr(hwin, "    Oct octal mode      roL roll stack\n");
  832. X    waddstr(hwin, "    Bin binary mode      Xy exchange x y\n");
  833. X    mybox(hwin);
  834. X    wrefresh(hwin);
  835. X    return (hwin);
  836. X}
  837. X
  838. X#ifndef ANSI_C
  839. X#include <errno.h>
  840. X#include <ctype.h>
  841. Xextern int errno;
  842. X
  843. Xunsigned long
  844. Xstrtoul(buf, trailing, base)
  845. Xchar *buf;
  846. Xchar **trailing;
  847. Xint base;
  848. X{
  849. X    int c;
  850. X    unsigned long ans;
  851. X
  852. X    ans = 0L;
  853. X
  854. X    while (isspace(*buf))
  855. X        buf++;
  856. X                    /* try to guess the base */
  857. X    if (base == 0) {
  858. X        if (*buf == '0') {
  859. X            base = 8;
  860. X            if (buf[1] == 'x' || buf[1] == 'X')
  861. X                base = 16;
  862. X        }
  863. X        else
  864. X            base = 10;
  865. X    }
  866. X                    /* skip over '0x' and '0X' */
  867. X    if (base == 16) {
  868. X        if (*buf == '0' && (buf[1] == 'x' || buf[1] == 'X'))
  869. X            buf += 2;
  870. X    }
  871. X
  872. X    while (1) {
  873. X        c = *buf;
  874. X        if (isdigit(c))
  875. X            c -= '0';
  876. X        else if (islower(c))
  877. X            c -= 'a' - 10;
  878. X        else if (isupper(c))
  879. X            c -= 'A' - 10;
  880. X        else            /* unrecognized character, so stop */
  881. X            break;
  882. X                    /* is this digit allowed? */
  883. X        if (c >= base)
  884. X            break;
  885. X
  886. X        if ((ULONG_MAX - (unsigned int) c) / (unsigned int) base < ans) {
  887. X            ans = ULONG_MAX;
  888. X            errno = ERANGE;
  889. X            break;
  890. X        }
  891. X        ans = ans * base + c;
  892. X        buf++;
  893. X    }
  894. X
  895. X    if (trailing)
  896. X        *trailing = buf;
  897. X
  898. X    return (ans);
  899. X}
  900. X#endif /* ANSI_C */
  901. SHAR_EOF
  902. if test 19008 -ne "`wc -c < 'rpn.c'`"
  903. then
  904.     echo shar: "error transmitting 'rpn.c'" '(should have been 19008 characters)'
  905. fi
  906. fi
  907. echo shar: "extracting 'rpn.1'" '(4028 characters)'
  908. if test -f 'rpn.1'
  909. then
  910.     echo shar: "will not over-write existing file 'rpn.1'"
  911. else
  912. sed 's/^X//' << \SHAR_EOF > 'rpn.1'
  913. X.TH RPN 1 local
  914. X.SH NAME
  915. Xrpn \- an HP-16c reverse polish notation (rpn) calculator
  916. X.SH SYNOPSIS
  917. X.B rpn
  918. X[
  919. X.B \-d
  920. X]
  921. X.SH DESCRIPTION
  922. X.I Rpn
  923. Xis a ``pop up'' calculator for Unix and MSDOS that is designed to
  924. Xoperate similar to the Hewlett-Packard HP-16c (Computer Scientist)
  925. Xcalculator.  It can operate in a floating point, hexidecimal, decimal,
  926. Xoctal, or binary mode.
  927. X.PP
  928. XThe
  929. X.I \-d
  930. Xoption is used to specify the number of decimal point precision that
  931. Xwill appear in the display.  The internal precision of the calculator is
  932. Xnot affected.
  933. X.PP
  934. XThe calculator appears on the screen as:
  935. X.PP
  936. X.RS 5
  937. X.nf
  938. X+---------------------------------------------+
  939. X|   Reverse Polish Notation calculator v1.1   |
  940. X|  +---------------------------------------+  |
  941. X|  |                                       |  |
  942. X|  +---------------------------------------+  |
  943. X|                                             |
  944. X|   a   b   c   d   e   f    7   8   9   /    |
  945. X|                                             |
  946. X|   ?  Flt Hex Dec Oct Bin   4   5   6   *    |
  947. X|                                             |
  948. X|   &   |  roL  Xy  ^H <cr>  1   2   3   -    |
  949. X|                      <cr>                   |
  950. X|  Quit ^   ~  Sto Rcl <cr>  0   .  Chs  +    |
  951. X|                                             |
  952. X+---------------------------------------------+
  953. X.fi
  954. X.RE
  955. X.PP
  956. XThe ``buttons'' that appear on the screen turn to inverse video when the
  957. Xappropriate key on the keyboard is pressed.
  958. X.PP
  959. XReverse polish notation is an operating logic that envolves the use of
  960. Xthe ``enter'' key in lieu of an equal sign.  To perform arithmetic,
  961. Xkey in the first number, press the ``enter'' key, key in the second
  962. Xnumber, and then press the operator.  For example, to add 2 plus 3,
  963. Xyou type:
  964. X.PP
  965. X.RS 5
  966. X2 ``enter'' 3 +.
  967. X.RE
  968. X.PP
  969. XThe current mode of the calculator is displayed in the last
  970. Xposition on the ``screen'' as a blank, 'h', 'd', 'o', or 'b' for the
  971. Xfloating point, hexidecimal, decimal, octal, and binary modes
  972. Xrespectively.
  973. X.PP
  974. XThe use of the hex, decimal, octal, or binary modes implies that
  975. Xfractional parts of numbers are discarded and that negative numbers are
  976. Xdisplayed as a 2's complement.
  977. X.SH COMMANDS
  978. XThe
  979. X.I rpn
  980. Xprogram can perform the following mathematical and logical functions:
  981. X.PP
  982. X.RS 5
  983. X.nf
  984. X.if n .ta 2.5i
  985. X.if t .ta 2i
  986. X\fB+\fP addition    \fB&\fP logical and
  987. X\fB-\fP subtraction    \fB|\fP logical or
  988. X\fB*\fP multiplication    \fB^\fP logical exculsive or
  989. X\fB/\fP division    \fB~\fP 1's complement
  990. X.fi
  991. X.RE
  992. X.PP
  993. XThe following operators are also available:
  994. X.TP
  995. X.B ?
  996. XHelp screen.  A pop-up help screen to explain the abreviations.
  997. X.TP
  998. X.B F
  999. XFloating point mode.  Numbers with decimal points and/or exponents may
  1000. Xbe used.  Exponents are entered with the 'e' and may be followed by an
  1001. Xoptional sign, as in 1.23e-12.
  1002. X.TP
  1003. X.B H
  1004. XHexidecimal mode.  Numbers use hexidecimal notation (digits in the range
  1005. Xof 0-9 and a-f).  The maximum hexidecimal number is 0xffffffff.  To
  1006. Xenter a hexidecimal digit in the range of a-f, you \fImust\fP use lower
  1007. Xcase letters.
  1008. X.TP
  1009. X.B D
  1010. XDecimal mode.  Numbers use decimal notation (digits in the range of
  1011. X0-9).  The maximum decimal number is 4294967295.
  1012. X.TP
  1013. X.B O
  1014. XOctal mode.  Numbers use octal notation (digits in the range of 0-7).
  1015. XThe maximum octal number is 0377777777777.
  1016. X.TP
  1017. X.B B
  1018. Xbinary mode.  Numbers use binary notation (the digits 0 and 1).  The
  1019. Xmaximum is 32 bits.
  1020. X.TP
  1021. X.B L
  1022. XRoll the stack.  The contents of the stack are ``rolled'' down by one
  1023. Xposition.
  1024. X.TP
  1025. X.B X
  1026. XExchange X and Y values.  The last two values on the stack (X and Y)
  1027. Xswap positions.
  1028. X.TP
  1029. X.B ^H
  1030. XThe backspace key, to correct input.
  1031. X.TP
  1032. X.B ^M
  1033. XThe ``enter'' key, shown as <cr> on the calculator.
  1034. X.TP
  1035. X.B Q
  1036. XQuit.  Exit the program.
  1037. X.TP
  1038. X.B S
  1039. XStore a value in a register.  Registers are numbered 0-9.  To store a value
  1040. Xin register 2, you enter S2.
  1041. X.TP
  1042. X.B R
  1043. XRecall a value from a register.  Registers are numbered 0-9.
  1044. X.TP
  1045. X.B C
  1046. XChange sign.  To enter a negative number, you first enter the number and 
  1047. Xthen change the sign.
  1048. X.SH BUGS
  1049. XMost operators are case sensitive.
  1050. X.SH "SEE ALSO"
  1051. Xdc(1), bc(1)
  1052. SHAR_EOF
  1053. if test 4028 -ne "`wc -c < 'rpn.1'`"
  1054. then
  1055.     echo shar: "error transmitting 'rpn.1'" '(should have been 4028 characters)'
  1056. fi
  1057. fi
  1058. echo shar: "extracting 'rpn.man'" '(5173 characters)'
  1059. if test -f 'rpn.man'
  1060. then
  1061.     echo shar: "will not over-write existing file 'rpn.man'"
  1062. else
  1063. sed 's/^X//' << \SHAR_EOF > 'rpn.man'
  1064. X
  1065. X
  1066. X
  1067. X     RPN(1)                       (local)                       RPN(1)
  1068. X
  1069. X
  1070. X
  1071. X     NAME
  1072. X          rpn - an HP-16c reverse polish notation (rpn) calculator
  1073. X
  1074. X     SYNOPSIS
  1075. X          rpn [ -d ]
  1076. X
  1077. X     DESCRIPTION
  1078. X          Rpn is a ``pop up'' calculator for Unix and MSDOS that is
  1079. X          designed to operate similar to the Hewlett-Packard HP-16c
  1080. X          (Computer Scientist) calculator.  It can operate in a
  1081. X          floating point, hexidecimal, decimal, octal, or binary mode.
  1082. X
  1083. X          The -d option is used to specify the number of decimal point
  1084. X          precision that will appear in the display.  The internal
  1085. X          precision of the calculator is not affected.
  1086. X
  1087. X          The calculator appears on the screen as:
  1088. X
  1089. X               +---------------------------------------------+
  1090. X               |   Reverse Polish Notation calculator v1.1   |
  1091. X               |  +---------------------------------------+  |
  1092. X               |  |                                       |  |
  1093. X               |  +---------------------------------------+  |
  1094. X               |                                             |
  1095. X               |   a   b   c   d   e   f    7   8   9   /    |
  1096. X               |                                             |
  1097. X               |   ?  Flt Hex Dec Oct Bin   4   5   6   *    |
  1098. X               |                                             |
  1099. X               |   &   |  roL  Xy  ^H <cr>  1   2   3   -    |
  1100. X               |                      <cr>                   |
  1101. X               |  Quit ^   ~  Sto Rcl <cr>  0   .  Chs  +    |
  1102. X               |                                             |
  1103. X               +---------------------------------------------+
  1104. X
  1105. X          The ``buttons'' that appear on the screen turn to inverse
  1106. X          video when the appropriate key on the keyboard is pressed.
  1107. X
  1108. X          Reverse polish notation is an operating logic that envolves
  1109. X          the use of the ``enter'' key in lieu of an equal sign.  To
  1110. X          perform arithmetic, key in the first number, press the
  1111. X          ``enter'' key, key in the second number, and then press the
  1112. X          operator.  For example, to add 2 plus 3, you type:
  1113. X
  1114. X               2 ``enter'' 3 +.
  1115. X
  1116. X          The current mode of the calculator is displayed in the last
  1117. X          position on the ``screen'' as a blank, 'h', 'd', 'o', or 'b'
  1118. X          for the floating point, hexidecimal, decimal, octal, and
  1119. X          binary modes respectively.
  1120. X
  1121. X          The use of the hex, decimal, octal, or binary modes implies
  1122. X          that fractional parts of numbers are discarded and that
  1123. X
  1124. X
  1125. X
  1126. X     Page 1
  1127. X
  1128. X
  1129. X
  1130. X
  1131. X
  1132. X
  1133. X     RPN(1)                       (local)                       RPN(1)
  1134. X
  1135. X
  1136. X
  1137. X          negative numbers are displayed as a 2's complement.
  1138. X
  1139. X     COMMANDS
  1140. X          The rpn program can perform the following mathematical and
  1141. X          logical functions:
  1142. X
  1143. X               + addition               & logical and
  1144. X               - subtraction            | logical or
  1145. X               * multiplication         ^ logical exculsive or
  1146. X               / division               ~ 1's complement
  1147. X
  1148. X          The following operators are also available:
  1149. X
  1150. X          ?    Help screen.  A pop-up help screen to explain the
  1151. X               abreviations.
  1152. X
  1153. X          F    Floating point mode.  Numbers with decimal points
  1154. X               and/or exponents may be used.  Exponents are entered
  1155. X               with the 'e' and may be followed by an optional sign,
  1156. X               as in 1.23e-12.
  1157. X
  1158. X          H    Hexidecimal mode.  Numbers use hexidecimal notation
  1159. X               (digits in the range of 0-9 and a-f).  The maximum
  1160. X               hexidecimal number is 0xffffffff.  To enter a
  1161. X               hexidecimal digit in the range of a-f, you must use
  1162. X               lower case letters.
  1163. X
  1164. X          D    Decimal mode.  Numbers use decimal notation (digits in
  1165. X               the range of 0-9).  The maximum decimal number is
  1166. X               4294967295.
  1167. X
  1168. X          O    Octal mode.  Numbers use octal notation (digits in the
  1169. X               range of 0-7).  The maximum octal number is
  1170. X               0377777777777.
  1171. X
  1172. X          B    binary mode.  Numbers use binary notation (the digits 0
  1173. X               and 1).  The maximum is 32 bits.
  1174. X
  1175. X          L    Roll the stack.  The contents of the stack are
  1176. X               ``rolled'' down by one position.
  1177. X
  1178. X          X    Exchange X and Y values.  The last two values on the
  1179. X               stack (X and Y) swap positions.
  1180. X
  1181. X          ^H   The backspace key, to correct input.
  1182. X
  1183. X          ^M   The ``enter'' key, shown as <cr> on the calculator.
  1184. X
  1185. X          Q    Quit.  Exit the program.
  1186. X
  1187. X          S    Store a value in a register.  Registers are numbered
  1188. X               0-9.  To store a value in register 2, you enter S2.
  1189. X
  1190. X
  1191. X
  1192. X     Page 2
  1193. X
  1194. X
  1195. X
  1196. X
  1197. X
  1198. X
  1199. X     RPN(1)                       (local)                       RPN(1)
  1200. X
  1201. X
  1202. X
  1203. X          R    Recall a value from a register.  Registers are numbered
  1204. X               0-9.
  1205. X
  1206. X          C    Change sign.  To enter a negative number, you first
  1207. X               enter the number and then change the sign.
  1208. X
  1209. X     BUGS
  1210. X          Most operators are case sensitive.
  1211. X
  1212. X     SEE ALSO
  1213. X          dc(1), bc(1)
  1214. X
  1215. X
  1216. X
  1217. X
  1218. X
  1219. X
  1220. X
  1221. X
  1222. X
  1223. X
  1224. X
  1225. X
  1226. X
  1227. X
  1228. X
  1229. X
  1230. X
  1231. X
  1232. X
  1233. X
  1234. X
  1235. X
  1236. X
  1237. X
  1238. X
  1239. X
  1240. X
  1241. X
  1242. X
  1243. X
  1244. X
  1245. X
  1246. X
  1247. X
  1248. X
  1249. X
  1250. X
  1251. X
  1252. X
  1253. X
  1254. X
  1255. X
  1256. X
  1257. X
  1258. X     Page 3
  1259. X
  1260. X
  1261. X
  1262. SHAR_EOF
  1263. if test 5173 -ne "`wc -c < 'rpn.man'`"
  1264. then
  1265.     echo shar: "error transmitting 'rpn.man'" '(should have been 5173 characters)'
  1266. fi
  1267. fi
  1268. exit 0
  1269. #    End of shell archive
  1270.  
  1271.  
  1272.